import { extend } from 'umi-request'
import { Toast } from 'vant'
import { getType } from './util'
import { REQUEST_PREFIX } from './constant.js'

const errorMessage = '系统繁忙，请稍后再试'
const codeMessage = {
  400: '发出的请求有误',
  404: '请求地址不存在',
  500: errorMessage,
  502: '网关错误',
  503: '服务不可用',
  504: '网关超时',
}
const defaultCustomerOption = {
  dataLevel: 'pure', // 是否返回简洁数据 'pure' | 'full'
  skipErrorMessage: false, // 是否忽略错误信息
  forbidClick: true, // 是否禁用点击
  getInfo: false, // 是否是查询类请求
}
const timeout = {
  timeoutId: undefined,
  startTimeout: (callback, delay) => {
    if (typeof callback !== 'function') {
      throw new Error('callback 需为函数')
    }
    clearTimeout(timeout.timeoutId)
    if (delay) {
      timeout.timeoutId = setTimeout(callback, delay)
    } else {
      callback()
    }
  },
  stopTimeout: () => clearTimeout(timeout.timeoutId),
}
const getCustomerOption = (ctx) => {
  const { req } = ctx
  return { ...defaultCustomerOption, ...req.options }
}

const request = extend({
  prefix: REQUEST_PREFIX,
  timeout: 10 * 1000,
  getResponse: true,
  errorHandler: (error) => {
    const { response, name } = error
    const { status, statusText } = response || {}
    const headers = new Headers(response?.headers)

    if (status) {
      Toast(codeMessage[status] || statusText || errorMessage)
    }
    if (name === 'CustomerError') {
      Toast(error.message)
    } else if (!response) {
      Toast('您的网络发生异常，无法连接服务器')
    }

    throw error
  },
})

// 中间件，统一处理返回数据
request.use(async (ctx, next) => {
  await next()
  const { data } = ctx.res
  const { message, retCode, data: dataValue } = data
  const { dataLevel, skipErrorMessage } = getCustomerOption(ctx)

  if (retCode !== 10000) {
    const error = new Error(message || errorMessage)
    error.name = 'CustomerError'
    if (!skipErrorMessage) {
      throw error
    }
  }
  ctx.res = dataLevel !== 'pure' ? data : dataValue
})

// 中间件，统一过滤空字段
request.use(async (ctx, next) => {
  const { filterEmptyData = true, data } = ctx.req.options
  if (filterEmptyData && getType(data) === 'object') {
    const fullData = {}
    Object.keys(data).forEach((key) => {
      if (![undefined, null, ''].includes(data[key])) {
        fullData[key] = data[key]
      }
    })
    if (Object.keys(fullData).length) {
      ctx.req.options.data = fullData
    } else {
      delete ctx.req.options.data
    }
  }
  await next()
})

// 中间件，统一处理loading，防止重复提交表单
request.use(async (ctx, next) => {
  const { forbidClick, getInfo } = getCustomerOption(ctx)
  const delay = getInfo ? 1000 : 0
  timeout.startTimeout(() => Toast.loading({ forbidClick }), delay)
  await next()
  timeout.stopTimeout()
  Toast.clear(false)
})

function get(url, params = {}, config = {}) {
  return request.get(url, { ...config, params })
}

function post(url, data = {}, config = {}) {
  return request.post(url, { ...config, data })
}

function getInfo(url, data = {}, config = {}) {
  return request.post(url, { getInfo: true, ...config, data })
}

export { request, get, post, getInfo }
